package com.maodou.core.datastore.db

import android.content.Context
import androidx.room.Room
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
import net.sqlcipher.database.SQLiteDatabase
import net.sqlcipher.database.SupportFactory
import android.util.Base64
import java.security.SecureRandom
import java.io.File
import androidx.core.content.edit

object DatabaseProvider {
    @Volatile
    private var INSTANCE: AppDatabase? = null

    private const val DB_NAME = "maodou.db"
    private const val PREF_FILE = "db_secure_prefs"
    private const val PREF_KEY_PASSPHRASE = "db_passphrase"
    private const val PREF_KEY_ENCRYPTED_INIT = "encrypted_initialized"

    fun get(context: Context): AppDatabase {
        return INSTANCE ?: synchronized(this) {
            INSTANCE ?: run {
                val appCtx = context.applicationContext
                // 显式加载 SQLCipher 原生库，避免在 release 下因裁剪/混淆导致的动态加载异常
                SQLiteDatabase.loadLibs(appCtx)

                ensureEncryptedInitialized(appCtx)
                val factory = SupportFactory(getOrCreatePassphrase(appCtx))
                Room.databaseBuilder(
                    appCtx,
                    AppDatabase::class.java,
                    DB_NAME
                ).openHelperFactory(factory)
                    .build()
            }.also { INSTANCE = it }
        }
    }

    private fun ensureEncryptedInitialized(context: Context) {
        val prefs = EncryptedSharedPreferences.create(
            context,
            PREF_FILE,
            MasterKey.Builder(context).setKeyScheme(MasterKey.KeyScheme.AES256_GCM).build(),
            EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
            EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
        )
        // 如果第一次切换到加密，删除旧的明文数据库，避免 Room 因为无法读取而崩溃
        val initialized = prefs.getBoolean(PREF_KEY_ENCRYPTED_INIT, false)
        if (!initialized) {
            val dbFile = context.getDatabasePath(DB_NAME)
            if (dbFile.exists()) {
                dbFile.delete()
                // 同时删除 -shm / -wal 避免残留
                File(dbFile.parentFile, "$DB_NAME-shm").delete()
                File(dbFile.parentFile, "$DB_NAME-wal").delete()
            }
            prefs.edit { putBoolean(PREF_KEY_ENCRYPTED_INIT, true) }
        }
    }

    private fun getOrCreatePassphrase(context: Context): ByteArray {
        val prefs = EncryptedSharedPreferences.create(
            context,
            PREF_FILE,
            MasterKey.Builder(context).setKeyScheme(MasterKey.KeyScheme.AES256_GCM).build(),
            EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
            EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
        )
        val existing = prefs.getString(PREF_KEY_PASSPHRASE, null)
        if (existing != null) return Base64.decode(existing, Base64.DEFAULT)

        val bytes = ByteArray(32)
        SecureRandom().nextBytes(bytes)
        prefs.edit { putString(PREF_KEY_PASSPHRASE, Base64.encodeToString(bytes, Base64.DEFAULT)) }
        return bytes
    }
}